package web

import (
	"fmt"
	"gitee.com/daichang01/my-basic-go/webook/internal/domain"
	"gitee.com/daichang01/my-basic-go/webook/internal/service"
	regexp "github.com/dlclark/regexp2"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"net/http"
)

// UserHandler 准备在它上面定义跟用户有关的路由,为了分组
type UserHandler struct {
	svc         *service.UserService
	emailExp    *regexp.Regexp
	passwordExp *regexp.Regexp
}

func NewUserHandler(svc *service.UserService) *UserHandler {
	const (
		emailRegexPattern = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$"
		// 和上面比起来，用 ` 看起来就比较清爽
		passwordRegexPattern = `^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,72}$`

		userIdKey = "userId"
		bizLogin  = "login"
	)
	//在这里预编译正则表达式
	return &UserHandler{
		svc:         svc,
		emailExp:    regexp.MustCompile(emailRegexPattern, regexp.None),
		passwordExp: regexp.MustCompile(passwordRegexPattern, regexp.None),
	}

}

func (u *UserHandler) RegisterRoutesV1(ug *gin.RouterGroup) {
	//分组注册,方便注册路由
	ug.POST("/signup", u.SignUp)
	ug.POST("/login", u.Login)
	ug.POST("/edit", u.Edit)
	ug.GET("/profile", u.Profile)
}

// handler定义在哪里，就让他在哪里注册，缺点是缺乏全局视野，可能和
func (u *UserHandler) RegisterRoutes(server *gin.Engine) {
	//分组注册,方便注册路由
	ug := server.Group("/users")
	ug.POST("/signup", u.SignUp)
	//server.POST("/users/login", func(context *gin.Context) {
	//
	//})
	ug.POST("/login", u.Login)
	ug.POST("/edit", u.Edit)
	ug.GET("/profile", u.Profile)
}

func (u *UserHandler) SignUp(context *gin.Context) {
	type SignUpReq struct {
		Email           string `json:"email"`
		ConfirmPassword string `json:"confirmPassword"`
		Password        string `json:"password"`
	}

	var req SignUpReq
	//将请求数据绑定到一个结构体变量 req 上，并检查是否有错误发生。
	//Bind方法会根据Content - Type来解析数据到req里面
	//解析错了，就会直接写回一个400的错误
	if err := context.Bind(&req); err != nil {
		return
	}

	isEmail, err := u.emailExp.MatchString(req.Email)
	if err != nil {
		context.String(http.StatusOK, "系统错误")
		return
	}
	if !isEmail {
		context.String(http.StatusOK, "你的邮箱格式不对")
		return
	}
	if req.ConfirmPassword != req.Password {
		context.String(http.StatusOK, "两次密码输入不一致")
		return
	}

	isPassword, err := u.passwordExp.MatchString(req.Password)
	if err != nil {
		context.String(http.StatusOK, "系统错误")
		return
	}
	if !isPassword {
		context.String(http.StatusOK, "密码必须大于8位,包含数字，特殊字符")
		return
	}
	//调用一下svc的方法、
	err = u.svc.SignUp(context, domain.User{
		Email:    req.Email,
		Password: req.Password,
	})
	if err == service.ErrUserDuplicateEmail {
		context.String(http.StatusOK, "邮箱冲突")
		return
	}
	if err != nil {
		context.String(http.StatusOK, "系统异常")
		return
	}
	//写回响应
	context.String(http.StatusOK, "注册成功")
	fmt.Println("%v", req)
	//数据库操作

}

func (u *UserHandler) Login(context *gin.Context) {
	type LoginReq struct {
		Email    string `json:"email"`
		Password string `json:"password"`
	}

	var req LoginReq
	if err := context.Bind(&req); err != nil {
		return
	}
	user, err := u.svc.Login(context, req.Email, req.Password)
	if err == service.ErrInvalidUserOrPassword {
		context.String(http.StatusOK, "用户名或密码不对")
		return
	}
	if err != nil {
		context.String(http.StatusOK, "系统错误·")
		return
	}
	//在这里登录成功
	//设置session
	sess := sessions.Default(context)
	sess.Set("userId", user.Id)
	//可加入参数
	sess.Options(sessions.Options{
		Secure:   true,
		HttpOnly: true,
		//一分钟过期
		MaxAge: 60,
	})
	sess.Save()
	context.String(http.StatusOK, "登录成功")
	return
}

func (u *UserHandler) Edit(context *gin.Context) {

}

func (u *UserHandler) Profile(context *gin.Context) {
	context.String(http.StatusOK, "这是我的profile")

}
